using System.Collections.Generic;
using Imaginarium.stats;
using GameEngine.animations;
using Imaginarium.items.equip;
using Imaginarium.jobs;
using System;
using GameEngine.Scenes;
using Imaginarium.XML;
using System.Xml;
using GameEngine.utils.console;

namespace Imaginarium.team
{
    public class Character: Actor
    {
        #region Attributes
        public int hp { get; set; }
        public int mp { get; set; }
        public int level { get; set; }
        public int baseExpDropped { get; set; }
        public int jobExpDropped { get; set; }
        public int idCharacter { get; set; }
        public string name { get; set; }
        public Stats stats { get; set; }
        public Team team { get; set; }
        public CharacterEquipment currentEquipment { get; set; }

        public List<ActiveSpecialState> actualSpecialState { get; set; }
        public bool dissapearAtDying;
        public TypeOfAttack attackType { get; set; } //should be erased
        #endregion

        #region Constructor-Clone
        public Character()
        {
            this.actualSpecialState = new List<ActiveSpecialState>();
            this.originType = OriginType.CENTER_DOWN;
            this.dissapearAtDying = true;
        }
        public Character(XmlElement node) :
            base(node)
        {
            this.hp = XmlHelper.getIntByTagname(node, XmlParameters.HP);
            this.mp = XmlHelper.getIntByTagname(node, XmlParameters.MP);
            this.level = XmlHelper.getIntByTagname(node, XmlParameters.LEVEL);
            //this.baseExpDropped; TO DO
            //this.jobExpDropped; TO DO
            //throw new Exception("sin base exp o job exp del xml");
            this.idCharacter = XmlHelper.getIntByTagname(node, XmlParameters.ID);
            this.name = XmlHelper.getStringByTagname(node, XmlParameters.NAME);
            this.stats = new Stats(XmlHelper.getXmlElementByTagname(node, XmlParameters.STATS));
            this.currentEquipment = new CharacterEquipment(XmlHelper.getXmlElementByTagname(node, XmlParameters.CHARACTER_EQUIPMENT_LIST));
            XmlNodeList actualSSList = node.GetElementsByTagName(XmlParameters.ACTUAL_SPECIAL_STATE_LIST);
            if (actualSSList.Count > 0)
            {
                actualSpecialState = new List<ActiveSpecialState>();
                foreach (XmlElement xe in actualSSList)
                {
                    actualSpecialState.Add(new ActiveSpecialState(xe));
                }
            }
        }
        #endregion

        #region Functionality
        public void sustractHp(int shp) {
            this.hp -= shp;
            if (this.hp < 0)
                this.hp = 0;
        }
        public void addHp(int ahp) {
            this.hp += ahp;
        }

        public void sustractMp(int smp)
        {
            this.mp -= smp;
            if (this.mp < 0)
                this.mp = 0;
        }
        public void addMp(int amp)
        {
            this.mp += amp;
        }
        public void levelUp() {
            level++;
        }
        
        public void dodgedAttack()
        {
            ImaginariumConsole.getInstance().write(this.name + " has avoided an attack");
        }

        public void receiveDamage() {
            ImaginariumConsole.getInstance().write(this.name + " received an attack");
        }

        public void receiveSpecialStates(List<DetailSpecialState> posibleStates) { 
            throw new NotImplementedException();
        }

        public void addSpecialState(ActiveSpecialState ss) {
            actualSpecialState.Add(ss);
        }

        public bool equip(Equipment eq,EquipmentPosition position){
            return currentEquipment.equip(eq, position);
        }

        public Stats getFinalStats() {
            Stats ans;
            ans = this.stats +
                (currentEquipment != null ? currentEquipment.getFinalEquipmentStats() : null) +
                this.getSpecialStateStats();
            return ans;
        }

        private Stats getSpecialStateStats() {
            Stats st = new Stats();
            foreach (ActiveSpecialState dss in actualSpecialState) {
                st += dss.specialState.Stats;
            }
            return st;
        }

        public int[] calcExpDropped() 
        {
            int[] exps = new int[2];
            exps[0] = (int)(baseExpDropped * (1 + level * CodeParameters.baseExpPerLevelMultiplier));
            exps[1] = (int)(jobExpDropped * (1 + level * CodeParameters.jobExpPerLevelMultiplier));
            return exps;
        }

        public bool isDead() 
        {
            if (hp <= 0)
                return true;
            else
                return false;
        }

        public bool canCast(SkillDetail sd) 
        {
            if (sd.calcMPCost() > this.mp)
                return false;
            else
                return true;
        }

        public TypeOfAttack getAttackType() 
        {
            return attackType;
        }
        public enum TypeOfAttack
        {
            melee,
            range,
            magic
        }
        #endregion

        #region Animations
        public void setAnimation(CharacterAnimations characterAnimation)
        {
            int i = 0;
            foreach (DetailAnimation da in detailAnimations) 
            {
                if (da is DetailAnimationCharacter &&
                    ((DetailAnimationCharacter)da).CharacterAnimations==characterAnimation) 
                {
                    currentAnimation = i;
                    break;
                }
                i++;
            }
        }
        public void setAnimation(string animationName)
        {
            int i = 0;
            foreach (DetailAnimation da in detailAnimations)
            {
                if (da.name.Equals(animationName))
                {
                    currentAnimation = i;
                    break;
                }
                i++;
            }
        }
        #endregion

        #region ICloneable Members
        public override object Clone()
        {
            Character newCharacter = (Character)base.Clone();
            newCharacter.hp = this.hp;
            newCharacter.idCharacter = this.idCharacter;
            newCharacter.level = this.idCharacter;
            newCharacter.baseExpDropped = this.baseExpDropped;
            newCharacter.jobExpDropped = this.jobExpDropped;
            newCharacter.mp = this.mp;
            newCharacter.name = this.name;
            newCharacter.stats = this.stats;
            if (this.currentEquipment != null)
            {
                newCharacter.currentEquipment = (CharacterEquipment)this.currentEquipment.Clone();
            }
            if (this.actualSpecialState != null && this.actualSpecialState.Count > 0)
            {
                foreach (ActiveSpecialState dSS in this.actualSpecialState)
                {
                    newCharacter.actualSpecialState.Add((ActiveSpecialState)dSS.Clone());
                }
            }

            newCharacter.attackType = this.attackType;

            return newCharacter;
        }
        #endregion

    }
}